package com.github.cuter44.wxcp.util;

import java.util.Map;
import java.util.HashMap;
import java.io.IOException;

import com.github.cuter44.wxcp.reqs.*;
import com.github.cuter44.wxcp.resps.*;
import com.alibaba.fastjson.*;

/** Token keeper
 * Keep minding the access token and JSSDK Ticket and their expiration, and automatically refresh if expired.
  * @deprecated To feature Token Distributing and form harmony, this class is deprecated, see issue #12 for guides.
*/
@Deprecated
public class WxcpTokenKeeper
{
  // CONFIG
    /** Switch to enable WxcpTokenKeeper to remember and recall instance with same corpsecret. Enabled by default.
     * <br />
     * If enabled, WxcpTokenKeeper keeps instances generated by <code>WxcpTokenKeeper.getInstance()</code>.
     * <code>getInstance()</code> returns same singleton for same appid respectively.
     * If disabled, <code>WxcpTokenKeeper.getInstance()</code> create new instance every time it is called,
     * without detecting if there is an existing one.
     * In such case, external restraint is expected (which means you are responsible for the implement).
     */
    public static boolean ENABLE_SINGLETON_MANAGEMENT = true;
    protected static HashMap<String, WxcpTokenKeeper> instances = new HashMap<String, WxcpTokenKeeper>();

  // CONSTRUCT
    protected String corpid;
    protected String corpsecret;

    protected String accessToken;
    protected long atExpiration;

    protected String jssdkTicket;
    protected long jtExpiration;

    protected WxcpTokenKeeper(String corpid, String corpsecret)
    {
        this.corpid = corpid;
        this.corpsecret = corpsecret;
        this.atExpiration = 0L;
        this.jtExpiration = 0L;

        return;
    }

    /** Construct an instance of WxcpTokenKeeper.
     * If <code>ENABLE_SINGLETON_MANAGEMENT</code> enabled, return singleton.
     */
    public static WxcpTokenKeeper getInstance(String corpid, String corpsecret)
    {
        if (!ENABLE_SINGLETON_MANAGEMENT)
            return(new WxcpTokenKeeper(corpid, corpsecret));

        // else
        WxcpTokenKeeper tk = WxcpTokenKeeper.instances.get(corpsecret);

        if (tk != null)
            return(tk);

        // else
        synchronized(WxcpTokenKeeper.instances)
        {
            tk = WxcpTokenKeeper.instances.get(corpsecret);

            if (tk != null)
                return(tk);

            // else
            tk = new WxcpTokenKeeper(corpid, corpsecret);
            WxcpTokenKeeper.instances.put(corpsecret, tk);
            return(tk);
        }
    }

  // ACCESS_TOKEN
    protected void retrieveAccessToken()
    {
        try
        {
            GettokenResponse resp = new Gettoken(this.corpid, this.corpsecret)
                .execute();

            this.accessToken = resp.getAccessToken();
            this.atExpiration = resp.getTmCreate() + (resp.getExpiresIn()*1000L);

            return;
        }
        catch (IOException ex)
        {
            throw(new RuntimeException(ex));
        }
    }

    /** @return this
     */
    public WxcpTokenKeeper forceRetrieveAccessToken()
    {
        this.retrieveAccessToken();

        return(this);
    }

    public String getAccessToken()
    {
        if (this.atExpiration > System.currentTimeMillis())
            return(this.accessToken);

        // else
        synchronized(this)
        {
            if (this.atExpiration > System.currentTimeMillis())
                return(this.accessToken);

            this.retrieveAccessToken();

            return(this.accessToken);
        }
    }

  // JSAPI_TICKET
    protected void retrieveJsapiTicket()
    {
        try
        {
            GetJsapiTicketResponse resp = new GetJsapiTicket(this.getAccessToken())
                .execute();

            this.jssdkTicket = resp.getTicket();
            this.jtExpiration = resp.getTmCreate() + (resp.getExpiresIn()*1000L);

            return;
        }
        catch (IOException ex)
        {
            throw(new RuntimeException(ex));
        }
    }

    /** @return this
     */
    public WxcpTokenKeeper forceRetrieveJsapiTicket()
    {
        this.retrieveJsapiTicket();

        return(this);
    }

    public String getJsapiTicket()
    {
        if (this.jtExpiration > System.currentTimeMillis())
            return(this.jssdkTicket);

        // else
        synchronized(this)
        {
            if (this.jtExpiration > System.currentTimeMillis())
                return(this.jssdkTicket);

            this.retrieveJsapiTicket();

            return(this.jssdkTicket);
        }
    }
}
